package com.piggymetrics.notification.service;

import com.gaea.tracker.ServiceTracker;
import com.gaea.tracker.common.Identifier;
import com.piggymetrics.notification.client.NotificationMongoServiceClient;
import com.piggymetrics.notification.domain.NotificationType;
import com.piggymetrics.notification.domain.Recipient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;

@Service
public class RecipientServiceImpl implements RecipientService {
	ThreadLocal<ServiceTracker> trackerThreadLocal = new ThreadLocal<ServiceTracker>();


	private final Logger log = LoggerFactory.getLogger(getClass());

	@Autowired
	private NotificationMongoServiceClient notificationMongoServiceClient;

	@Override
	public Recipient findByAccountName(String accountName) {
		if ( trackerThreadLocal.get() == null ){
			trackerThreadLocal.set(ServiceTracker.newInstance("notification-service"));
		}
		ServiceTracker tracker = trackerThreadLocal.get();
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getRequest();
		HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getResponse();
		tracker.trackInEvent(request, response);

		Assert.hasLength(accountName);

		Identifier identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		Recipient recipient = notificationMongoServiceClient.findByAccountName(accountName,identifier.getUrl(),
						identifier.getServiceName(), identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		tracker.trackBackOutEvent(response);
		return recipient;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Recipient save(String accountName, Recipient recipient) {
		if ( trackerThreadLocal.get() == null ){
			trackerThreadLocal.set(ServiceTracker.newInstance("notification-service"));
		}
		ServiceTracker tracker = trackerThreadLocal.get();
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getRequest();
		HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
						.getRequestAttributes()).getResponse();
		tracker.trackInEvent(request, response);

		recipient.setAccountName(accountName);
		recipient.getScheduledNotifications().values()
				.forEach(settings -> {
					if (settings.getLastNotified() == null) {
						settings.setLastNotified(new Date());
					}
				});

		Identifier identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		notificationMongoServiceClient.save(recipient,identifier.getUrl(),identifier.getServiceName(),
						 identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());

		log.info("recipient {} settings has been updated", recipient);

		tracker.trackBackOutEvent(response);
		return recipient;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List<Recipient> findReadyToNotify(NotificationType type) {

		if ( trackerThreadLocal.get() == null ){
			trackerThreadLocal.set(ServiceTracker.newInstance("notification-service"));
		}
		ServiceTracker tracker = trackerThreadLocal.get();

		Identifier identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		List<Recipient> list = null;

		switch (type) {
			case BACKUP:
				list = notificationMongoServiceClient.findByReadyForBackup(identifier.getUrl(),identifier.getServiceName(),
								identifier.getRequestId(), identifier.getStage(), identifier.getCallId());
				break;
			case REMIND:
				list = notificationMongoServiceClient.findByReadyForRemind(identifier.getUrl(),identifier.getServiceName(),
								identifier.getRequestId(), identifier.getStage(), identifier.getCallId());
				break;
			default:
				throw new IllegalArgumentException();
		}

		tracker.trackBackInEvent(identifier.getCallId());
		return list;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void markNotified(NotificationType type, Recipient recipient) {
		recipient.getScheduledNotifications().get(type).setLastNotified(new Date());

		if ( trackerThreadLocal.get() == null ){
			trackerThreadLocal.set(ServiceTracker.newInstance("notification-service"));
		}
		ServiceTracker tracker = trackerThreadLocal.get();

		Identifier identifier = tracker.generateIdentifier();
		tracker.trackOutEvent(identifier.getCallId());

		notificationMongoServiceClient.save(recipient,identifier.getUrl(),identifier.getServiceName(),
						identifier.getRequestId(), identifier.getStage(), identifier.getCallId());

		tracker.trackBackInEvent(identifier.getCallId());
	}
}
